#include <iostream>
#include <fstream>
#include <cmath>

using namespace std;


class Interpolator
{
    const static double step = 0.1;    

public:
    
    static void lagrange(const char* infile, const char* outfile);
	static void chebyshev(const char* infile, const char* outfile);
	static double f(double x);
};


double Interpolator::f(double x)
{
    return 1.0/(1.0 + 12*x*x);
}
    

void Interpolator::lagrange(const char* infile, const char* outfile)
{
    ifstream in(infile);
	ofstream out(outfile);
	ofstream lvalues("lvalues");
	
	if(!in)
	{
	    cout <<"\nerror opening input file : "  <<infile <<"\n";
		exit(1);
	}
	
	if(!out)
	{
	    cout <<"\nerror opening output file : "  <<outfile <<"\n";
		exit(1);
	}
	
	
	int n;  //number of intervals
	in >>n;
	
	double* x = new double[n+1];
	double* y = new double[n+1];
	
	//read x's and y's
	for(int i=0; i<=n ;++i)
	{
	    in >>x[i] >>y[i];
		cout <<x[i] <<"   " <<y[i] <<"\n";
		
	}
	
	in.close();
	
	//calculate lagrange values and generate dataset with interval of 'step'
	for(double currentX=x[0]; currentX < x[n]; currentX = currentX+step)
	{
	    //do lagrange 
		double sum=0.0;
		for(int i=0; i<=n; ++i)
		{
			//calculate L
			double upperL=1,lowerL=1,L=1;		
			for(int j=0; j<=n; ++j)
			{
				if(i==j) continue;

				upperL= upperL * (currentX-x[j]);
				lowerL= lowerL * (x[i]-x[j]);
			}
			
			L= upperL/lowerL;
			
			sum= sum + y[i] * L;
			
			lvalues <<"y(" <<i <<") is : " <<y[i] <<"  and L(" <<i <<") is : " <<L <<"\n";
			
		}
		
		lvalues <<"x : " <<currentX <<"  "  <<"   y :  " <<sum <<"\n\n";
		out <<currentX <<"  "  <<sum <<"\n";
	}
	
	out.close();
	lvalues.close();

}


void Interpolator::chebyshev(const char* infile, const char* outfile)
{
    double PI= 3.1415926535;
	
    //ifstream in(infile);
	ofstream out(outfile);
	ofstream tvalues("tvalues");
	/*if(!in)
	{
	    cout <<"\nerror opening input file : "  <<infile <<"\n";
		exit(1);
	}*/
	
	if(!out)
	{
	    cout <<"\nerror opening output file : "  <<outfile <<"\n";
		exit(1);
	}
	
	int n=10;  //number of intervals
	//in >>n;
	
	double* x = new double[n+1];
	double* y = new double[n+1];
	double* t = new double[n+1];
	double* node = new double[n+1];
	double *c = new double[n+1];
	
	//read x's and y's
	for(int i=0; i<=n ;++i)
	{
	    x[i]=i;
		node[i]= cos((2*double(i)+1)*(PI/(2*double(n)+2)));
		y[i]= f(node[i]);
		cout <<x[i] <<"   " <<y[i] <<"\n";
	}
	
	//calculate cj's
	for(int k=0; k<=n; ++k)
	{
		double z= (2*k+1)*(PI/(2*double(n)+2));
		for(int j=0; j<=n; ++j)
		{
			c[j]= c[j] + y[k] * cos(double(j) * z);
			
		}
	}
	
	for(int i=0;i<=n;++i)
	{
		if(i==0)
		{
			c[i]=c[i]/(double(n)+1);
			
		}
		else
		{
			c[i]= (2 * c[i])/(double(n)+1);
		} 
		
		tvalues <<"c("  <<i  <<") is : "  <<c[i]  <<"\n";
	}
	
	tvalues <<"\n\n";

	//calculate chebyshev values and generate dataset with interval of 'step'
	for(double currentX=-1; currentX <= 1; currentX = currentX+step)
	{
	    //do chebyshev 
		
		//calculate t's
		t[0]=1;
		t[1]=currentX;
		for(int i=2; i<=n; ++i)
		{
		    t[i]= 2*currentX* t[i-1] - t[i-2];
			
			tvalues <<"T(" <<i <<") is  " <<t[i] <<"\n";
		}
		
		tvalues <<"\n\n";
		
		double sum=0.0;
		
		for(int i=0;i<=n;++i)
		{
			sum= sum + c[i] * t[i];
		}
		
		out <<currentX <<"  "  <<sum <<"\n";
	}
		/*
		for(int i=0; i<=n; ++i)
		{
			//calculate c
			//double c=0;
			/*if(i==0)
			{
			    for(int j=0; j<=n; ++j)
				{
				    c= c + y[j] ;
				}
			
				c= (1/(1+double(n))) * c;
			}
			else
			
			    for(int k=0; k<=n; ++k)
				{
				    double z= (2*k+1)*(PI/(2*double(n)+2));
				    for(int j=0; j<=n; ++j)
					{
						c= c + y[k] * cos(double(j) * z);
						//c= c + y[j] * cos((double(i)*PI*(2*double(j)+1))/(2*double(n)+2));
					}
				}
				
				c= (2/(double(n)+1)) * c;
			//}
			
			//sum= sum + c*t[i];
			
		//}
			
		//cout <<currentX <<"  "  <<sum <<"\n";
		out <<currentX <<"  "  <<sum <<"\n";
	}*/
	
	out.close();
	tvalues.close();
}

int main(int argc, char* argv[])
{
    Interpolator::lagrange(argv[1], argv[2]);
	//Interpolator::chebyshev(argv[1], argv[2]);

    return 0;
}

